/*=============================================================
  
  PROGRAMMING TECHNIQUES FOR SUPERCOMPUTERS

  Timing code skeleton

=============================================================*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "timing.h"
#include <math.h>
#include <fstream>


double timeStamp()
{ 
  struct timeval tp;
  gettimeofday(&tp, NULL); 
  return((double)(tp.tv_sec + tp.tv_usec/1000000.0)); 
}

int min( int a, int b)
{
  if ( a < b ) return a;
  else return b;
}

int main(int argc, char *argv[]) 
{
  double wcTimeStart,wcTimeEnd,cpuTimeStart,cpuTimeEnd,wcTime;

  std::fstream f;
  
  /* Part2 */
  int repeat = 1;
  int N;
 
  double *a;
  double *b;
  double *c;
  double *d;
   
   //loop with different initialzations for c[]
   for (int task = 1; task <= 3; ++task) {
      //open output file
      if (task == 1)
         f.open("data_a.txt",std::ios::out);
      if (task == 2)
         f.open("data_b.txt",std::ios::out);
 	   if (task == 3)
 	      f.open("data_c.txt",std::ios::out);
        
      //loop with different values for N
      for (int i = 0; i <= 3; ++i) { 
         
         if (i == 0)
            N = 400;
         if (i == 1)
            N = 5000;
         if (i == 2)
            N = 1e5;
         if (i == 3)
            N = 1e6;         
         std::cout << "Part " << task << ",N:" << N << std::endl;   
         a = new double[N];
         b = new double[N];
         c = new double[N];
         d = new double[N];
         
         //array initialization
         for (size_t i = 0; i < N; ++i) {
  	    b[i] = i*1.0;
  	    if (task == 1)
            {
               c[i] = 1.3*i+10;
               if (c[i] <= 0) std::cout << "c[i] <= 0" << std::endl;
            }
            if (task == 2)
            {
               c[i] = -1.3*i-2.5;
               if (c[i] >= 0) std::cout << "c[i] >= 0" << std::endl;
            }
            if (task == 3)
            {
               c[i] = (rand()%101)/50.0-1.0;
               if (c[i] < -1 || c[i] >1) std::cout << "c[i] <-1 or >1" << std::endl;
            }
            d[i] = 2.0*i+10.0;
         }
         
        repeat = 1;
      	wcTime = 0;
	    for(; wcTime<.1; repeat*=2) {
            wcTimeStart = timeStamp();
            
            for(int r=0; r<repeat; ++r) {
               #pragma novector
               for (int i = 0; i < N; ++i) {
                  if (c[i]>0)
                     a[i] = b[i] + c[i] * d[i];
                  else
                     a[i] = b[i] - c[i] * d[i];
                     
	            }
         		if(a[N-1]<0) std::cout << a[N-1] << std::endl; // fools the compiler
            }
            wcTimeEnd = timeStamp();
            wcTime=wcTimeEnd-wcTimeStart;
         }
         repeat/=2;
     	   f << N <<"           " << (2*N*repeat)/(wcTime*1000000) << std::endl;
  	      delete [] a;
  	      delete [] b;
  	      delete [] c;
  	      delete [] d;
      }   
      f.close();
      
   }
 
  return 0;
}
